/*
 * adc.c
 *
 * Created: 2013/12/25 16:15:06
 *  Author: alivehex
 */ 
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#include "uart.h"
#include "gpio.h"
#include "iolgt8f0xa.h"
#include "hardware.h"


// ADC input = 1/3 battery volt
#define BATTRY_LOW_VOLT_MV	3.0
#define BATTRY_HIGH_VOLT_MV	3.3

#define BATTERY_LOW_VALUE	204	// ((BATTRY_LOW_VOLT_MV / 3 ) * 256 / 1.25)
#define BATTERY_HIGH_VALUE	224 // ((BATTRY_HIGH_VOLT_MV / 3) * 256 / 1.25)

typedef enum {
	SIGNAL_LOWBAT,
	SIGNAL_OKBAT,
} bat_stata_t;

/* channel = n, n=0~7:PA0~PA7  */
void ADCInit() {
	// uint16_t retval;
	_CONFIG_IO_HIZ(ADC_INPUT_PORT, (1 << ADC_INPUT_PIN));
	_CONFIG_IO_OUTPUT(LOW_BATTERY_LED_SIGNAL_PORT, 
		(1 << LOW_BATTERY_LED_SIGNAL_PIN));
	_SET_IO(LOW_BATTERY_LED_SIGNAL_PORT, (1 << LOW_BATTERY_LED_SIGNAL_PIN));
	
	ADCSRA = 0;			//disable ADC
	ADMUX = ((2 << 6) | (0 << 5) | ADC_INPUT_PIN);
	
	//enable ADC
	ADCSRA = (1 << 7);	
	_delay_us(5);
	
	// enable the ADC interrupt
	ADCSRA |= (1 << 3);
}

void ADCStart() {
	ADCSRA |= (1 << 6);		//enable conversion
}

ISR(ADC_vect) {
	uint16_t ADCValue = ADCL;
	static bat_stata_t batState = SIGNAL_OKBAT;
	static uint16_t batAvrValue = 0;
	
	ADCValue = (ADCH << 8) | ADCValue;
	
	if(batAvrValue) {
		batAvrValue = (batAvrValue + ADCValue) >> 1;
	} else {
		batAvrValue = ADCValue;
	}
	
	// kprintf("%d %d %d\r\n", batAvrValue, BATTERY_LOW_VALUE, BATTERY_HIGH_VALUE);
	switch(batState) {
	case SIGNAL_OKBAT:
		_CONFIG_IO_HIZ(LOW_BATTERY_LED_SIGNAL_PORT, (1 << LOW_BATTERY_LED_SIGNAL_PIN));
		if(batAvrValue < BATTERY_LOW_VALUE) {
			// low battery warning
			// _PORT_(LOW_BATTERY_LED_SIGNAL_PORT) ^= (1 << LOW_BATTERY_LED_SIGNAL_PIN);
			_CONFIG_IO_OUTPUT(LOW_BATTERY_LED_SIGNAL_PORT, (1 << LOW_BATTERY_LED_SIGNAL_PIN));
			_CLR_IO(LOW_BATTERY_LED_SIGNAL_PORT, (1 << LOW_BATTERY_LED_SIGNAL_PIN));
			batState = SIGNAL_LOWBAT;
		}
	break;
	case SIGNAL_LOWBAT:
		_PORT_(LOW_BATTERY_LED_SIGNAL_PORT) ^= (1 << LOW_BATTERY_LED_SIGNAL_PIN);
		
		if(batAvrValue > BATTERY_HIGH_VALUE) {
			// set input HiZ to turn off LED
			// _CONFIG_IO_HIZ(LOW_BATTERY_LED_SIGNAL_PORT, (1 << LOW_BATTERY_LED_SIGNAL_PIN));
			batState = SIGNAL_OKBAT;
		}
	break;	
	}
	
#if (0)	
	if(batValue < BATTERY_LOW_VALUE) {
		// low battery warning
		_PORT_(LOW_BATTERY_LED_SIGNAL_PORT) ^= (1 << LOW_BATTERY_LED_SIGNAL_PIN);
		// _CLR_IO(LOW_BATTERY_LED_SIGNAL_PORT, (1 << LOW_BATTERY_LED_SIGNAL_PIN));	
	} else if(batValue > BATTERY_HIGH_VALUE) {
		// set input HiZ to turn off LED
		_CONFIG_IO_HIZ(LOW_BATTERY_LED_SIGNAL_PORT, (1 << LOW_BATTERY_LED_SIGNAL_PIN));
	}
#endif
}